package org.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.jsonwebtoken.Claims;
import org.example.domain.Article;
import org.example.domain.ArticleBody;
import org.example.domain.Category;
import org.example.domain.User;
import org.example.filter.aop.CheckToken;
import org.example.mapper.ArticleBodyMapper;
import org.example.mapper.ArticleMapper;
import org.example.param.ArticleAddParam;
import org.example.param.ArticleAuthorParam;
import org.example.param.ArticleFuzzyParam;
import org.example.param.ArticleUpdateParam;
import org.example.service.ArticleService;
import org.example.service.CategoryService;
import org.example.service.TagService;
import org.example.service.UserService;
import org.example.utils.HttpCode;
import org.example.utils.JwtUtil;
import org.example.utils.RequestContextUtil;
import org.example.utils.Result;
import org.example.vo.ArticleVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;

@Service
public class ArticleServiceImpl implements ArticleService {
    @Resource
    private ArticleMapper articleMapper;
    @Resource
    private ArticleBodyMapper articleBodyMapper;
    @Resource
    private TagService tagService;
    @Resource
    private UserService userService;
    @Resource
    private CategoryService categoryService;
    @Resource
    private ThreadServiceImpl threadService;

    /**
     * 先添加articleBody 得到这个bodyId
     * 添加article 等到 articleId
     * 添加 articleTag
     * @param articleAddParam
     * @return
     */
    @Override
    @Transactional // 事务
    @CheckToken
    public Result add(ArticleAddParam articleAddParam) {
        // ArticleBody
        ArticleBody articleBody = ArticleBody.builder()
                .content(articleAddParam.getContent())
                .isDelete(0).build();
        int total1 = articleBodyMapper.insert(articleBody);
        if (total1 == 0){
            return Result.fail(HttpCode.INSERT_ERROR);
        }
        Long bodyId = articleBody.getId();
        // Article
        Claims claims = JwtUtil.decryptToken(RequestContextUtil.getRequest().getHeader("Authorization"));
        if (claims == null){
            return Result.fail(HttpCode.TOKEN_ERROR);
        }
        String id = claims.getId();
        Article article = Article.builder()
                .createDate(System.currentTimeMillis())
                .summary(articleAddParam.getSummary())
                .title(articleAddParam.getTitle())
                .authorId(Long.valueOf(id))
                .bodyId(bodyId)
                .categoryId(articleAddParam.getCategoryId())
                .commentCounts(0)
                .viewCounts(0)
                .weight(0)
                .isDelete(0).build();
        int total2 = articleMapper.insert(article);
        if (total2 == 0){
            return Result.fail(HttpCode.INSERT_ERROR);
        }
        Long articleId = article.getId();
        // Article_Tag
        int total3 = tagService.addArticle(articleId, articleAddParam.getTagIds());
        if (total3 == 0){
            return Result.fail(HttpCode.INSERT_ERROR);
        }
        return Result.success(articleId);
    }

    /**
     * 判断是否是作者本人删除
     * 根据id删除,
     * 删除ArticleTag
     * 删除ArticleBody
     * 删除Article
     * @param id
     * @return
     */
    @Override
    @CheckToken
    @Transactional
    public Result delete(Long id) {
        if (id == null || id <= 0){
            return Result.fail(HttpCode.PARAM_ERROR);
        }
        // 判断文章是否存在
        if (!isExist(id)){
            return Result.fail(HttpCode.ARTICLE_NO_EXIST);
        }
        // 判断是否是作者本人删除
        Claims claims = JwtUtil.decryptToken(RequestContextUtil.getRequest().getHeader("Authorization"));
        if (claims == null){
            return Result.fail(HttpCode.TOKEN_ERROR);
        }
        Long userId = Long.valueOf(claims.getId());
        if (getAuthorIdById(id) != null && userId != getAuthorIdById(id).longValue()){
            return Result.fail(HttpCode.NO_AUTHOR);
        }
        // 删除ArticleTag
        tagService.deleteArticle(id);
        // 删除ArticleBody
        articleBodyMapper.deleteById(getBodyIdById(id));
        // 删除Article
        int total = articleMapper.deleteById(id);
        if (total == 0){
            return Result.fail(HttpCode.DELETE_ERROR);
        }
        return Result.success();
    }

    /**
     * 判断是否是本人修改
     * 修改ArticleTag: 先删除 再添加
     * 修改ArticleBody
     * 修改Article
     * @param articleUpdateParam
     * @return
     */
    @Override
    @CheckToken
    @Transactional
    public Result update(ArticleUpdateParam articleUpdateParam) {
        // 判断文章是否存在
        if (!isExist(articleUpdateParam.getId())){
            return Result.fail(HttpCode.ARTICLE_NO_EXIST);
        }
        // 判断是否是本人修改
        Claims claims = JwtUtil.decryptToken(RequestContextUtil.getRequest().getHeader("Authorization"));
        if (claims == null){
            return Result.fail(HttpCode.TOKEN_ERROR);
        }
        Long userId = Long.valueOf(claims.getId());
        if (getAuthorIdById(articleUpdateParam.getId()) != null && userId.longValue() != getAuthorIdById(articleUpdateParam.getId())){
            return Result.fail(HttpCode.NO_AUTHOR);
        }
        // 修改ArticleTag: 先删除 再添加
        tagService.deleteArticle(articleUpdateParam.getId());
        tagService.addArticle(articleUpdateParam.getId(),articleUpdateParam.getTagIds());
        // 修改ArticleBody
        ArticleBody articleBody = ArticleBody.builder()
                .id(getBodyIdById(articleUpdateParam.getId()))
                .content(articleUpdateParam.getContent())
                .build();
        articleBodyMapper.updateById(articleBody);
        // 修改Article
        Article article = Article.builder()
                .id(articleUpdateParam.getId())
                .summary(articleUpdateParam.getSummary())
                .title(articleUpdateParam.getTitle())
                .categoryId(articleUpdateParam.getCategoryId())
                .build();
        int total = articleMapper.updateById(article);
        if (total == 0){
            return Result.fail(HttpCode.UPDATE_ERROR);
        }
        return Result.success();
    }

    /**
     * articleVo
     * @return
     */
    @Override
    public Result all() {
        List<Article> articleList = articleMapper.selectList(null);
        List<ArticleVo> articleVoList = copyArticleVoList(articleList);
        return Result.success(articleVoList);
    }

    @Override
    public Result fuzzy(ArticleFuzzyParam articleFuzzyParam) {

        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        // 条件
        wrapper.like(StringUtils.hasText(articleFuzzyParam.getTitle()),Article::getTitle,articleFuzzyParam.getTitle());
        wrapper.ge(articleFuzzyParam.getStartDate()!=null,Article::getCreateDate,articleFuzzyParam.getStartDate());
        wrapper.le(articleFuzzyParam.getEndDate()!=null,Article::getCreateDate,articleFuzzyParam.getEndDate());
        if (!CollectionUtils.isEmpty(articleFuzzyParam.getTagIds())){
            // 根据标签模糊查询,先查ArticleTag,查出对应的articleId
            List<Long> articleIds = tagService.findArticleIdById(articleFuzzyParam.getTagIds());
            if (CollectionUtils.isEmpty(articleIds)){
                return Result.success(new Page<>(articleFuzzyParam.getPageNum(),articleFuzzyParam.getPageSize()));
            }
            wrapper.in(Article::getId,articleIds);
        }
        wrapper.eq(articleFuzzyParam.getCategoryId()!=null,Article::getCategoryId,articleFuzzyParam.getCategoryId());
        // 排序 ,  权重排 , 时间排序 , 阅读数
        if (StringUtils.hasText(articleFuzzyParam.getOrder())){
            // 按时间
            if (articleFuzzyParam.getOrder().equalsIgnoreCase("time")) wrapper.orderByDesc(Article::getCreateDate);
            // 按阅读数
            if (articleFuzzyParam.getOrder().equalsIgnoreCase("hot")) wrapper.orderByDesc(Article::getViewCounts);
        }else{
            wrapper.orderByDesc(Article::getWeight).orderByDesc(Article::getCreateDate).orderByDesc(Article::getViewCounts);
        }

        // 查询
        Page<Article> articlePage = articleMapper.selectPage(new Page<>(articleFuzzyParam.getPageNum(), articleFuzzyParam.getPageSize()),
                wrapper);
        // 构造返回的数据
        List<ArticleVo> articleVoList = copyArticleVoList(articlePage.getRecords());
        Page<ArticleVo> result = new Page<>(articleFuzzyParam.getPageNum(),articleFuzzyParam.getPageSize());
        result.setTotal(articlePage.getTotal()); // 页数
        result.setRecords(articleVoList); // 数据
        return Result.success(result);
    }

    /**
     * 注: 增加阅读数
     * @param id
     * @return
     */
    @Override
    public Result findArticleById(Long id) {
        if (id == null){
            return Result.fail(HttpCode.PARAM_ERROR);
        }
        Article article = articleMapper.selectById(id);
        // 异步线程更新阅读数
        threadService.updateViewCounts(id);
        return Result.success(copyArticleVo(article));
    }

    @Override
    public Result findArticleByAuthor(ArticleAuthorParam articleAuthorParam) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getAuthorId,articleAuthorParam.getAuthorId());
        Page<Article> articlePage = articleMapper.selectPage(new Page<>(articleAuthorParam.getPageNum(), articleAuthorParam.getPageSize()),
                wrapper);
        List<ArticleVo> articleVoList = copyArticleVoList(articlePage.getRecords());
        return Result.success(copyPage(articleVoList,articleAuthorParam.getPageNum(),articleAuthorParam.getPageSize(),articlePage.getTotal()));
    }


    private final  Page copyPage(List articleVoList,Integer pageNum,Integer pageSize,Long total){
        Page page = new Page(pageNum,pageSize);
        page.setTotal(total);
        page.setRecords(articleVoList);
        return page;
    }

    private final List<ArticleVo> copyArticleVoList(List<Article> articleList){
        List<ArticleVo> articleVoList = new LinkedList<>();
        articleList.forEach(article -> {
            ArticleVo articleVo = copyArticleVo(article);
            articleVoList.add(articleVo);
        });
        return articleVoList;
    }

    private final ArticleVo copyArticleVo(Article article){
        ArticleVo articleVo = ArticleVo.builder()
                .id(article.getId())
                .title(article.getTitle())
                .content(getContentByBodyId(article.getBodyId()))
                .summary(article.getSummary())
                .createDate(article.getCreateDate())
                .viewCounts(article.getViewCounts())
                .commentCounts(article.getCommentCounts())
                .weight(article.getWeight())
                .user((User) userService.findUserById(article.getAuthorId()).getData())
                .category((Category) categoryService.findCategoryById(article.getCategoryId()).getData())
                .tags(tagService.findTagsByArticleId(article.getId()))
                .build();
        return articleVo;
    }


    private final String getContentByBodyId(Long id){
        ArticleBody articleBody = articleBodyMapper.selectById(id);
        if (articleBody == null) return null;
        return articleBody.getContent();
    }

    private final boolean isExist(Long id){
        return articleMapper.selectById(id) != null;
    }

    private final Long getAuthorIdById(Long id){
        return articleMapper.selectById(id).getAuthorId();
    }

    private final Long getBodyIdById(Long id){
        return articleMapper.selectById(id).getBodyId();
    }
}
